package com.tian.service.impl;

import cn.hutool.core.bean.BeanUtil;
import com.alibaba.fastjson.JSON;
import com.tian.common.CommonResult;
import com.tian.common.PageResult;
import com.tian.config.ThreadDelayTaskService;
import com.tian.dto.ChargeUserLoginResDto;
import com.tian.dto.message.ChargeSystemMessagePageReqDto;
import com.tian.dto.message.ChargeSystemMessageUpdateReqDto;
import com.tian.dto.message.ChargeUserSystemMessageRespDto;
import com.tian.entity.ChargeSystemMessage;
import com.tian.entity.ChargeSystemMessageContent;
import com.tian.enums.ResultCode;
import com.tian.mapper.ChargeSystemMessageMapper;
import com.tian.service.ChargeSystemMessageService;
import com.tian.util.ChargeMarketRedisKeyPrefix;
import com.tian.util.ConstantsUtil;
import com.tian.util.StringUtil;
import com.tian.util.UserCacheUtil;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.*;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

/**
 * {@code @description:} 我的站内信
 *
 * @author tianwc 公众号：Java后端技术全栈
 * 在线刷题 1200+java面试题和1000+篇技术文章：<a href="https://woaijava.cc/">博客地址</a>
 * {@code @date:} 2024-08-07 17:55
 * {@code @version:} 1.0
 */
@Slf4j
@Service
public class ChargeSystemMessageServiceImpl implements ChargeSystemMessageService {
    @Resource
    private ChargeSystemMessageMapper chargeSystemMessageMapper;
    @Resource
    private RedissonClient redissonClient;
    @Resource
    private ThreadDelayTaskService threadDelayTaskService;

    @Override
    public CommonResult<Boolean> update(ChargeSystemMessageUpdateReqDto chargeSystemMessageUpdateReqDto) {
        ChargeUserLoginResDto user = UserCacheUtil.getUser();
        ChargeSystemMessage chargeSystemMessage = new ChargeSystemMessage();
        BeanUtil.copyProperties(chargeSystemMessageUpdateReqDto, chargeSystemMessage);
        chargeSystemMessageMapper.updateByPrimaryKey(chargeSystemMessage);
        try {
            RMap<Long, String> messageMap = redissonClient.getMap(ChargeMarketRedisKeyPrefix.USER_SYSTEM_MESSAGE_MAP_KEY + user.getId());
            messageMap.put(chargeSystemMessage.getId(), JSON.toJSONString(chargeSystemMessage));
        } catch (Exception e) {
            log.error("缓存操作失败，删除站内信缓存失败，站内信id={}", chargeSystemMessageUpdateReqDto.getId());
            threadDelayTaskService.delayUpdateUserMSystemMessageCache(ChargeMarketRedisKeyPrefix.USER_SYSTEM_MESSAGE_MAP_KEY + user.getId(),
                    chargeSystemMessage, user.getId(), ConstantsUtil.DELAY_TIME);
        }
        return CommonResult.success(Boolean.TRUE);
    }

    @Override
    public CommonResult<PageResult<List<ChargeUserSystemMessageRespDto>>> page(ChargeSystemMessagePageReqDto chargeSystemMessagePageReqDto) {
        ChargeUserLoginResDto user = UserCacheUtil.getUser();
        RList<Long> list = redissonClient.getList(ChargeMarketRedisKeyPrefix.USER_SYSTEM_MESSAGE_LIST_KEY + user.getId());
        int size = list.size();
        List<Long> messageIdList = list.range((chargeSystemMessagePageReqDto.getCurrentPage() - 1) * chargeSystemMessagePageReqDto.getPageSize(),
                (chargeSystemMessagePageReqDto.getCurrentPage() - 1) * chargeSystemMessagePageReqDto.getPageSize() + chargeSystemMessagePageReqDto.getPageSize());

        if (CollectionUtils.isEmpty(messageIdList)) {
            log.error("没有站内信");
            return CommonResult.success();
        }

        RMap<Long, String> messageMap = redissonClient.getMap(ChargeMarketRedisKeyPrefix.USER_SYSTEM_MESSAGE_MAP_KEY + user.getId());
        List<ChargeUserSystemMessageRespDto> chargeSystemMessageRespDtoList = new ArrayList<>();
        for (Long messageId : messageIdList) {
            String cache = messageMap.get(messageId);
            if (StringUtil.isBlank(cache)) {
                continue;
            }
            ChargeSystemMessage chargeSystemMessage = JSON.parseObject(cache, ChargeSystemMessage.class);

            RBucket<String> bucket = redissonClient.getBucket(ChargeMarketRedisKeyPrefix.USER_SYSTEM_MESSAGE_CONTENT_ID_KEY + chargeSystemMessage.getMessageId());
            ChargeSystemMessageContent chargeSystemMessageContent = JSON.parseObject(bucket.get(), ChargeSystemMessageContent.class);
            ChargeUserSystemMessageRespDto chargeUserSystemMessageRespDto = getChargeUserSystemMessageRespDto(chargeSystemMessage, chargeSystemMessageContent);
            //数据返回
            chargeSystemMessageRespDtoList.add(chargeUserSystemMessageRespDto);
        }

        PageResult<List<ChargeUserSystemMessageRespDto>> pageResult = PageResult.setData(size, chargeSystemMessagePageReqDto.getPageSize(), size / chargeSystemMessagePageReqDto.getPageSize(),
                chargeSystemMessagePageReqDto.getCurrentPage(), chargeSystemMessageRespDtoList);
        return CommonResult.success(pageResult);
    }

    private static ChargeUserSystemMessageRespDto getChargeUserSystemMessageRespDto(ChargeSystemMessage chargeSystemMessage, ChargeSystemMessageContent chargeSystemMessageContent) {
        ChargeUserSystemMessageRespDto chargeUserSystemMessageRespDto = new ChargeUserSystemMessageRespDto();
        chargeUserSystemMessageRespDto.setId(chargeSystemMessage.getId());
        chargeUserSystemMessageRespDto.setIsRead(chargeSystemMessage.getIsRead());
        chargeUserSystemMessageRespDto.setMessageId(chargeSystemMessageContent.getId());
        chargeUserSystemMessageRespDto.setSendTime(chargeSystemMessage.getSendTime());
        chargeUserSystemMessageRespDto.setUserId(chargeSystemMessage.getUserId());
        chargeUserSystemMessageRespDto.setTitle(chargeSystemMessageContent.getTitle());
        chargeUserSystemMessageRespDto.setContent(chargeSystemMessageContent.getContent());
        return chargeUserSystemMessageRespDto;
    }

    @Override
    public CommonResult<ChargeUserSystemMessageRespDto> findById(Long id) {
        ChargeUserLoginResDto user = UserCacheUtil.getUser();
        //从缓存hash中获取改用的站内信信息
        //userId:{
        // messageId:JSON.toJSON(ChargeSystemMessage)
        //}
        RMap<Long, String> messageMap = redissonClient.getMap(ChargeMarketRedisKeyPrefix.USER_SYSTEM_MESSAGE_MAP_KEY + user.getId());
        String cache = messageMap.get(id);
        //如果hash中没有缓存，则从数据库中获取，再放入缓存中
        if (StringUtil.isBlank(cache)) {
            ChargeSystemMessage chargeSystemMessage = chargeSystemMessageMapper.selectByPrimaryKey(id);
            //存空对象
            if (chargeSystemMessage == null) {
                //站内信已不存在
                return CommonResult.failed(ResultCode.MESSAGE_NO_EXIST);
            }
            //判断是不是当前登录用户的
            if (!chargeSystemMessage.getUserId().equals(user.getId())) {
                log.error("站内信不是当前登录用户的，id={}，userId={}", id, user.getId());
                return CommonResult.failed(ResultCode.PARAMETER_ERROR);
            }
            messageMap.put(id, JSON.toJSONString(chargeSystemMessage));


            RBucket<String> bucket = redissonClient.getBucket(ChargeMarketRedisKeyPrefix.USER_SYSTEM_MESSAGE_CONTENT_ID_KEY + chargeSystemMessage.getMessageId());

            ChargeSystemMessageContent chargeSystemMessageContent = JSON.parseObject(bucket.get(), ChargeSystemMessageContent.class);

            RList<Long> list = redissonClient.getList(ChargeMarketRedisKeyPrefix.USER_SYSTEM_MESSAGE_LIST_KEY + user.getId());
            if (!list.contains(id)) {
                list.add(id);
            }
            RScoredSortedSet<String> scoredSortedSet = redissonClient.getScoredSortedSet(ChargeMarketRedisKeyPrefix.USER_SYSTEM_MESSAGE_SET_KEY);
            if (!scoredSortedSet.contains(id)) {
                setExpiredDate(chargeSystemMessage, scoredSortedSet);
            }

            ChargeUserSystemMessageRespDto chargeUserSystemMessageRespDto = getChargeUserSystemMessageRespDto(chargeSystemMessage, chargeSystemMessageContent);
            return CommonResult.success(chargeUserSystemMessageRespDto);

        }

        ChargeSystemMessage chargeSystemMessage = JSON.parseObject(cache, ChargeSystemMessage.class);

        //再从缓存中获取站内信内容
        RBucket<String> bucket = redissonClient.getBucket(ChargeMarketRedisKeyPrefix.USER_SYSTEM_MESSAGE_CONTENT_ID_KEY + chargeSystemMessage.getMessageId());

        ChargeSystemMessageContent chargeSystemMessageContent = JSON.parseObject(bucket.get(), ChargeSystemMessageContent.class);

        //组装参数返回
        ChargeUserSystemMessageRespDto chargeUserSystemMessageRespDto = getChargeUserSystemMessageRespDto(chargeSystemMessage, chargeSystemMessageContent);
        return CommonResult.success(chargeUserSystemMessageRespDto);
    }

    private void setExpiredDate(ChargeSystemMessage chargeSystemMessage, RScoredSortedSet<String> scoredSortedSet) {
        LocalDateTime expiredDateTime = chargeSystemMessage.getSendTime().toInstant()
                .atZone(ZoneId.systemDefault())
                .toLocalDateTime()
                .plusMonths(3);  // 添加 3 个月
        Date expired = Date.from(expiredDateTime.atZone(ZoneId.systemDefault()).toInstant());
        String value = chargeSystemMessage.getId() + ConstantsUtil.SET_MESSAGE_SPLIT + expired + ConstantsUtil.SET_MESSAGE_SPLIT + chargeSystemMessage.getUserId();
        scoredSortedSet.add(expired.getTime(), value);
    }

    @Override
    public CommonResult<Boolean> delete(Long id) {

        ChargeUserLoginResDto user = UserCacheUtil.getUser();
        chargeSystemMessageMapper.deleteByPrimaryKey(id);

        RList<Long> list = redissonClient.getList(ChargeMarketRedisKeyPrefix.USER_SYSTEM_MESSAGE_LIST_KEY + user.getId());
        list.remove(id);

        RMap<Long, String> messageMap = redissonClient.getMap(ChargeMarketRedisKeyPrefix.USER_SYSTEM_MESSAGE_MAP_KEY + user.getId());
        messageMap.remove(id);

        RScoredSortedSet<String> scoredSortedSet = redissonClient.getScoredSortedSet(ChargeMarketRedisKeyPrefix.USER_SYSTEM_MESSAGE_SET_KEY);
        scoredSortedSet.remove(id);

        return CommonResult.success(Boolean.TRUE);
    }
}
